from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.context_processors import csrf
from django.template.defaultfilters import unordered_list
from django.views.decorators.cache import never_cache
from blog.models import Post, Tag, Category, Link
import markdown
import datetime
import logging
import sys
import re


reload(sys)
sys.setdefaultencoding("utf-8")

POSTS_PER_PAGE = 15


def post_archive():
    date_list = [post.publish_datetime.strftime('%Y-%m') for post in Post.objects.all()]
    result = dict()
    for date in date_list:
        if result.has_key(date):
            result[date] += 1
        else:
            result[date] = 1
    return sorted(result.items(), key=lambda x: x[0])


def get_category_widget_as_html():
    query_set = Category.objects.all()
    query_set_as_html = list()
    category_html_tpl = lambda depth, content, count: "%s<a href='/category/%s'>%s</a> (%s)<br>" % ("\--"*depth, content, content, count)
    for category in query_set:
        query_set_as_html.append(category_html_tpl(category.level, category.content, category.post_count))
    return '\n'.join(query_set_as_html)


def get_post(condition_value, condition_field=list(), query_method='iexact', combiner='and'):
    posts = dict()
    if 'category' in condition_field:
        condition = {
            'content__%s' % query_method: condition_value
        }
        for cate in Category.objects.select_related().filter(**condition):
            posts['category'] = cate.post_set.all()

    if 'tag' in condition_field:
        condition = {
            'content__%s' % query_method: condition_value
        }
        tags = Tag.objects.prefetch_related().filter(**condition)
        if tags:
            posts['tag'] = tags[0].post_tag.all()
        else:
            posts['tag'] = []

    if 'year' in condition_field:
        if type(condition_value) == int:
            posts['year'] = Post.objects.filter(publish_time__year=condition_value)
        else:
            posts['year'] = []

    if 'month' in condition_field:
        if type(condition_value) == int:
            posts['month'] = Post.objects.filter(publish_time__month=condition_value)
        else:
            posts['month'] = []
    if 'day' in condition_field:
        if type(condition_value) == int:
            posts['day'] = Post.objects.filter(publish_time__day=condition_value)
        else:
            posts['day'] = []
    if 'post_title' in condition_field:
        condition = {
            'title__%s' % query_method: condition_value
        }
        posts['post_title'] = Post.objects.filter(**condition)

    if 'post_content' in condition_field:
        posts['post_content'] = Post.objects.filter(content__contains=condition_value)

    if not condition_field:
        condition_field = ['category', 'tag', 'year', 'month', 'day', 'post_title', 'post_content']
        return get_post(condition_value, condition_field, 'contains', 'or')
    if combiner == 'and':
        return reduce(lambda x, y: list(set(x) & set(y)), posts.values())
    else:
        return reduce(lambda x, y: list(set(x) | set(y)), posts.values())


def add_base_data(template_name):
    BASE_RESPONSE_DATA = {
        # 'categories': Category.objects.all(),
        'categories': get_category_widget_as_html(),
        'tags': Tag.objects.all(),
        'archive': post_archive(),
        'links': Link.objects.all()
    }
    def _add_base_data(func):
        def __add_base_data(*args, **kwargs):
            request = args[0]
            posts = func(*args, **kwargs)
            response_data = {
                'posts': posts,
                'isAdminUser': request.user.is_authenticated()
            }
            response_data.update(BASE_RESPONSE_DATA)
            response_data.update(csrf(request))
            return render_to_response(template_name, response_data)

        return __add_base_data

    return _add_base_data


def paginated():
    def _paginated(fn):
        def __paginated(*args, **kwargs):
            request = args[0]
            posts_list = fn(*args, **kwargs)
            paginator = Paginator(posts_list, POSTS_PER_PAGE)
            try:
                posts = paginator.page(request.GET.get('page'))
            except PageNotAnInteger:
                posts = paginator.page(1)
            except EmptyPage:
                posts = paginator.page(paginator.num_pages)
            return posts

        return __paginated

    return _paginated


@add_base_data('index.html')
@paginated()
def index(request):
    logging.error(request.user, request.user.is_authenticated())
    return Post.objects.all()


@add_base_data('post_view.html')
def post_view(request, title):
    posts = Post.objects.filter(title__iexact=title)
    if posts.exists():
        post = posts[0]
        post.view_count += 1
        post.save()
        post.content = markdown.markdown(post.content)
        return post
    return posts


@add_base_data('index.html')
@paginated()
def category_view(request, content):
    return get_post(content, ['category'])


@add_base_data('index.html')
@paginated()
def tag_view(request, content):
    return get_post(content, ['tag'])


@add_base_data('index.html')
@paginated()
def date_view(request, year, month=None, day=None):
    selection_posts = dict()
    selection_posts['year'] = get_post(year, ['year'])
    if not month is None:
        selection_posts['month'] = get_post(month, ['month'])
    if not day is None:
        selection_posts['day'] = get_post(day, ['day'])
    return reduce(lambda x, y: list(set(x) & set(y)), selection_posts.values())


@add_base_data('index.html')
@paginated()
def search_view(request, content=None):
    if content is None:
        return index(request)
    else:
        return get_post(content)


def send_mail(request):
    if request.method == 'GET':
        if request.GET.has_key('cmd'):
            if not request.GET['cmd'] == 'backupDB':
                return HttpResponse('')
        else:
            return HttpResponse('')
    now = datetime.datetime.now()

    def dump_data(database):
        import subprocess

        CMD = 'mysqldump -u%s -p%s %s' % (database['USER'], database['PASSWORD'], database['NAME'])
        db = subprocess.Popen(CMD, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
        db_stdout, db_stderr = db.communicate()
        if db_stderr:
            logging.error(db_stderr)
            return None
        else:
            return db_stdout

    def zip_data(data):
        import zipfile
        from StringIO import StringIO

        buf = StringIO()
        with zipfile.ZipFile(buf, 'w') as db_zip:
            db_zip.writestr('%s.sql' % now.strftime('%Y-%m-%d_%H-%M-%S'), data, zipfile.ZIP_DEFLATED)
        return buf.getvalue()

    def send(dst_address, attach_data):
        from django.core.mail import EmailMessage


        subject = '[%s] backup db' % now.strftime('%Y-%m-%d %H:%M:%S')
        body = 'statistic'
        from_email = 'donvan@donvan.info'
        to = (dst_address,)
        attachments = ('%s.zip' % now.strftime('%Y-%m-%d_%H-%M-%S'), attach_data, 'application/zip')
        bcc = None
        connection = None
        headers = None
        cc = None

        email = EmailMessage(
            subject,
            body,
            from_email,
            to,
            bcc,
            connection,
            headers,
            cc,
        )
        email.attach(*attachments)
        try:
            email.send()
        except Exception, e:
            logging.error(e)
        else:
            logging.info('db backup ok. size: %s' % len(attach_data))

    from django.conf import settings

    logging.basicConfig(format='%(asctime)s - %(levelname)-7s - %(filename)s:%(funcName)s:%(lineno)s - %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')

    sql_data = dump_data(settings.DATABASES['default'])
    if sql_data:
        zip_sql_data = zip_data(sql_data)
        with open('test.zip', 'w') as f:
            f.write(zip_sql_data)
        send(settings.ADMINS[0][1], zip_sql_data)
    return HttpResponse('backup ok\n')
